package Basics;
import java.util.Vector;



public class Rule 
{
	
	Atom Head;
	
	Vector<Atom> Body = new Vector<Atom>();
    
	double weight;
    
    boolean isFullyInst = false;

    

	public Rule (){}
    
	public Rule (Atom head, double weight,  Atom... body)
    {
    	this.Head = head;
    	this.weight = weight;
    	for (Atom P : body) 
		{
			this.Body.add(P);
	    }
    }
	
	
	
	public Rule (Atom head, double weight,  Vector<Atom> body)
    {
    	this.Head = head;
    	this.weight = weight;
    	this.Body = body;
    }
	
	
	/*************************************************************************************************************/
	/** Title: Rule																				
	/** Description: Copy constructor				
	/*************************************************************************************************************/
	
	public Rule (Rule other)
	{
		for (Atom atom : other.Body) 
		{
			this.Body.add(new Atom(atom));
		}
		
		this.Head = new Atom(other.Head);
		this.weight = other.weight;
		this.isFullyInst = other.isFullyInst;
	}
	
	
	
    public Vector<Atom> getBody() 
    {
		return Body;
	}
    
    
    
	public void setBody(Atom... body) 
	{
		for (Atom P : body) 
		{
			Body.add(P);
	    }
	}
	
	
	
	public Atom getHead() 
	{
		return Head;
	}
	
	
	
	public void setHead(Atom head) 
	{
		Head = head;
	}
	
	
	
	public double getWeight() 
	{
		return weight;
	}
	
	
	
	public void setWeight(double weight)
	{
		this.weight = weight;
	}
	
	
	public boolean isFullyInst() 
    {
		this.CheckFullyInst();
		return isFullyInst;
	}

	
	
	/*************************************************************************************************************/
	/** Title: CheckFullyInst																				
	/** Description: Checks if the atom is fully inst. with constants or are there still vars in it				
	/*************************************************************************************************************/
	
	public void CheckFullyInst()
	{
		boolean retVal = this.Head.isFullyInst() ? true : false;
		for (Atom atom : this.Body) 
		{
			if (false == atom.isFullyInst())
			{
				retVal = false;
			}
		}
		
		this.isFullyInst = retVal;
	}

	
	
	/*************************************************************************************************************/
	/** Title: SwapVarInRule																				
	/** Description: Swaps two Protons in the same location in the inputed atom. 
	/** useful for inst. of constants in atoms
	/*************************************************************************************************************/
	
	public void SwapVarInRule (Proton oldP, Proton newP)
	{
		if ( true == this.Head.getParams().contains(oldP) )
		{
			Head.SwapInAtom(oldP, newP);
		}
		
		for (Atom atom : this.Body) 
		{
			if ( true == atom.getParams().contains(oldP) ) 
			{
				atom.SwapInAtom(oldP, newP);
			}
		}
	}
	
	
	
	/*************************************************************************************************************/
	/** Title: SwapToInstAtomAndPartiallyInst																				
	/** Description: Use for inst. atom with constants in rule and updating the rule
	/*************************************************************************************************************/
	
	public void SwapToInstAtomAndPartiallyInst (Atom oldA, Atom newA)
	{
		for (int i = 0; i < newA.getParams().size(); ++i)
		{
			if (oldA.getParams().elementAt(i) instanceof Var && newA.getParams().elementAt(i) instanceof Constant) 
			{
				Proton var = oldA.getParams().elementAt(i);
				Proton constant = newA.getParams().elementAt(i);
				this.SwapVarInRule(var, constant);
			}
		}
		
		this.isFullyInst();
	}	
	
	
	
	/*************************************************************************************************************/
	/** Title: CotainedInBody																				
	/** Description: checks if a group of atoms is contained in body of rule. use in pattern
	/*************************************************************************************************************/
	
	public boolean CotainedInBody (Vector<Atom> atomVec)
	{
		boolean retVal = true;
		for (Atom atom : atomVec) 
		{
			if (false == this.getBody().contains(atom))
			{
				retVal = false;
			}
		}
		
		return retVal;
	}
	
	
	
	public String toString ()
	{
		String retVal = this.Head.toString() + " :-";
		for (Atom atom : this.Body) 
		{
			retVal += " " + atom.toString() + ",";
		}
		
		retVal = retVal.substring(0,retVal.length()-1) + ".";
		return retVal;
	}
	
	
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((Body == null) ? 0 : Body.hashCode());
		result = prime * result + ((Head == null) ? 0 : Head.hashCode());
		result = prime * result + (isFullyInst ? 1231 : 1237);
		long temp;
		temp = Double.doubleToLongBits(weight);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Rule other = (Rule) obj;
		if (Body == null) {
			if (other.Body != null)
				return false;
		} else if (!Body.equals(other.Body))
			return false;
		if (Head == null) {
			if (other.Head != null)
				return false;
		} else if (!Head.equals(other.Head))
			return false;
		if (isFullyInst != other.isFullyInst)
			return false;
		if (Double.doubleToLongBits(weight) != Double
				.doubleToLongBits(other.weight))
			return false;
		return true;
	}




}
